package com.example.demo.heima.reactor;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * ******************************************************
 *
 * @author liugh9
 * @version 1.0
 * @classname PollerIO
 * @description 从Reactor
 * @date 2023/08/12 16:09
 * <p>
 * ******************************************************
 */
public class PollerIO extends ServerThead {

    private final Server server;

    private final LinkedBlockingQueue<SocketChannel> acceptorQueue;

    public PollerIO(String name, Server server) {
        super(name);
        this.server = server;
        this.acceptorQueue = new LinkedBlockingQueue<>();
    }

    public void addAcceptedConnection(SocketChannel socketChannel) {
        this.acceptorQueue.offer(socketChannel);
        weakUpSelector();
    }


    @Override
    public void run() {
        while (!server.stopped) {
            doSelect();
            doAcceptedConnections();
        }
        closeSelector();
    }

    private void doAcceptedConnections() {
        SocketChannel socketChannel;
        while (!server.stopped && (socketChannel = acceptorQueue.poll()) != null) {
            try {
                socketChannel.register(this.selector, SelectionKey.OP_READ);
            } catch (ClosedChannelException e) {
                e.printStackTrace();
            }
        }
    }

    private void doSelect() {
        try {
            this.selector.select();
            Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                if (!key.isValid()) {
                    continue;
                }
                if (key.isReadable() || key.isWritable()) {
                    handIO(key);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void handIO(SelectionKey key) {
        if (key.isReadable()) {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            ByteBuffer readBuffer = ByteBuffer.allocate(256);
            try {
                int i = socketChannel.read(readBuffer);
                if (i > 0) {
                    // 将数据封装成一个任务扔给线程池做业务
                    BusTask task = new BusTask(readBuffer, socketChannel);
                    server.addTask(task);
                }

            } catch (IOException e) {
                try {
                    socketChannel.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
        if (key.isWritable()) {

        }
    }
}
